/**
 *	\file AKCPPTTTStateMaintainer.cpp
 *  
 *  \section desc_sec Description
 *  Description
 *  
 *  \if copyright
 *  	Copyright 2008 Ben Chen. All rights reserved.
 *  \endif
 *  
 *  \section hist_sec Change History:
 *  	-	1/22/08		BC		Created this file
 *  
 *  <hr>
 *  \addtogroup AKCPP
 *  @{
 */

#include "AKCommon.h"
#include "AKCPPTTTStateMaintainer.h"

#include <vector>
using namespace std;

AKCPPTTTStateMaintainer::AKCPPTTTStateMaintainer(unsigned int aNumOfSides)
: PARENT(aNumOfSides)
{
	winners = new vector<AKSideIndex>();
	reachableCells = new vector<AKCellIndex>();
	somePieces	= new vector<AKPiece>();
	allPieces	= new vector<AKPiece>();
	movedPieces	= new vector<AKMove>();
}

AKCPPTTTStateMaintainer::~AKCPPTTTStateMaintainer()
{
	delete winners;
}

// State methods
void AKCPPTTTStateMaintainer::backToInitialState()
{
	for (int i = 0; i < NUM_CELLS; ++i)
	{
		cells[i].cell = i;
		cells[i].piece = NSNotFound;
		cells[i].side = NSNotFound;
	}
	
	nextPlayer	= BLACK;
	lastMove	= AKZeroMove;
}

bool AKCPPTTTStateMaintainer::performMove(const AKMove newMove)
{
	bool retVal = false;
	
	if (cells[newMove.dstCell].piece == NSNotFound)
	{
		cells[newMove.dstCell].piece = newMove.piece;
		cells[newMove.dstCell].side  = newMove.side;
		
		retVal = true;
	}
	
	lastMove = newMove;
	nextPlayer = (nextPlayer == BLACK) ? WHITE : BLACK;
	
	return retVal;	
}

bool AKCPPTTTStateMaintainer::canUndo()
{
	bool retVal;
	
	if (lastMove.piece != NSNotFound && lastMove.dstCell != NSNotFound)
		retVal = true;
	else
		retVal = false;
	
	return retVal;	
}

bool AKCPPTTTStateMaintainer::undo()
{
	bool retVal;
	
	if (canUndo())
	{
		// Only one time of undo is supported here.
		cells[lastMove.dstCell] = AKZeroPiece;
		lastMove = AKZeroMove;
	}
	else
		retVal = false;
	
	return retVal;
}

// Player related
const AKSideIndex AKCPPTTTStateMaintainer::getNextPlayerSide()
{
	return nextPlayer;
}

const vector<AKSideIndex>* AKCPPTTTStateMaintainer::getWinners()
{
	AKSideIndex retVal = NSNotFound;
	
	// 0 1 2
	// 3 4 5
	// 6 7 8
	
	// Three in a row
	if (cells[0].side != NSNotFound && cells[0].side == cells[1].side && cells[1].side == cells[2].side)
		retVal = cells[0].side;
	else if (cells[3].side != NSNotFound && cells[3].side == cells[4].side && cells[4].side == cells[5].side)
		retVal = cells[3].side;
	else if (cells[6].side != NSNotFound && cells[6].side == cells[7].side && cells[7].side == cells[8].side)
		retVal = cells[6].side;
	// Three in a column
	else if (cells[0].side != NSNotFound && cells[0].side == cells[3].side && cells[3].side == cells[6].side)
		retVal = cells[0].side;
	else if (cells[1].side != NSNotFound && cells[1].side == cells[4].side && cells[4].side == cells[7].side)
		retVal = cells[1].side;
	else if (cells[2].side != NSNotFound && cells[2].side == cells[5].side && cells[5].side == cells[8].side)
		retVal = cells[2].side;
	// Three in a diagnal
	else if (cells[0].side != NSNotFound && cells[0].side == cells[4].side && cells[4].side == cells[7].side)
		retVal = cells[0].side;
	else if (cells[2].side != NSNotFound && cells[2].side == cells[4].side && cells[4].side == cells[6].side)
		retVal = cells[2].side;
	
	winners->clear();
	winners->insert(winners->end(),retVal);
	return winners;
}

const AKMove AKCPPTTTStateMaintainer::getAlternativeMoveForNextPlayer()
{
	// TODO: return something resonable
	return AKZeroMove;
}

// Piece information
const vector<AKPiece>* AKCPPTTTStateMaintainer::getPlaceablePiecesAtCell(const AKCellIndex)
{
	// There's only one kind of piece
	AKPiece aPiece;
	aPiece.side		= nextPlayer;
	aPiece.piece	= 0;	// Only one kind of piece
	aPiece.cell		= NSNotFound;	// we don't care about cell here

	somePieces->clear();
	somePieces->insert(somePieces->begin(), aPiece);
	return somePieces;
}

const vector<AKCellIndex>* AKCPPTTTStateMaintainer::getReachableCellsForPiece(const AKPiece piece)
{
	// In Tic-Tac-Toe (also in GO, Othello, Gomoku, etc..), pieces are NOT allowed to move.
	reachableCells->clear();
	return reachableCells;
}

const vector<AKPiece>*	AKCPPTTTStateMaintainer::getCreatedPieces()
{
	return somePieces;
}

const vector<AKPiece>*	AKCPPTTTStateMaintainer::getElminatedPieces()
{
	somePieces->clear();	// No piece is eliminated in Tic-Tac-Toe
	return somePieces;
}

const vector<AKMove>*	AKCPPTTTStateMaintainer::getMovedPieces()
{
	movedPieces->clear();	// No piece is moved in Tic-Tac-Toe
	return movedPieces;
}

const vector<AKPiece>*	AKCPPTTTStateMaintainer::getAllPieces()
{
	allPieces->clear();
	for (unsigned int i = 0; i < 9; ++i)
	{
		if (cells[i].side != NSNotFound)
			allPieces->insert(allPieces->begin(), cells[i]);
	}

	return allPieces;
}

/** @} */

